package com.zhijian.warehouse.manage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import com.zhijian.util.BeanUtil;
import com.zhijian.util.page.Page;
import com.zhijian.warehouse.manage.dao.StoreAllotRecordMapper;
import com.zhijian.warehouse.manage.entity.dto.stock.StockActionDto;
import com.zhijian.warehouse.manage.entity.dto.stock.StockStorageDto;
import com.zhijian.warehouse.manage.entity.po.StoreAllotRecord;
import com.zhijian.warehouse.manage.entity.po.StoreAllotRecordProduct;
import com.zhijian.warehouse.manage.entity.po.Warehouse;
import com.zhijian.warehouse.manage.entity.vo.request.*;
import com.zhijian.warehouse.manage.entity.vo.response.*;
import com.zhijian.warehouse.manage.enums.CodingEnum;
import com.zhijian.warehouse.manage.enums.DelFlagEnum;
import com.zhijian.warehouse.manage.enums.StockActionEnum;
import com.zhijian.warehouse.manage.enums.StoreEnum;
import com.zhijian.warehouse.manage.service.*;
import com.zhijian.warehouse.manage.util.AssertCommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 调拨单记录业务处理层
 *
 * @author auto
 * @version: 1.0
 * @date 2024-11-03 15:30:31
 */
@Slf4j
@Service
public class StoreAllotRecordServiceImpl implements StoreAllotRecordService {

    @Autowired
    private StoreAllotRecordMapper mapper;

    @Autowired
    private StoreLockService storeLockService;

    @Autowired
    private StoreAllotRecordProductService storeAllotRecordProductService;

    @Autowired
    private StoreService storeService;

    @Autowired
    private ProductService productService;

    @Autowired
    private WarehouseService warehouseService;

    @Override
    public StoreAllotRecord selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public StoreAllotRecordVo selectVoById(Long id) {
        StoreAllotRecordVo storeAllotRecordVo = mapper.selectVoById(id);
        if (BeanUtil.isNotEmpty(storeAllotRecordVo))
            storeAllotRecordVo.setSaveOrUpdateVoList(storeAllotRecordProductService.selectList(StoreAllotRecordProductSearchVo.builder().storeAllotRecordId(id).build()));
        return storeAllotRecordVo;
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        StoreAllotRecord storeAllotRecord = this.selectById(id);
        AssertCommonUtil.check(storeAllotRecord.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue(), "当前调拨单已审核通过，不能删除");
        storeAllotRecordProductService.deleteByCondition(StoreAllotRecordProductSearchVo.builder().storeAllotRecordId(id).build());
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    @Transactional
    public void deleteByIdList(List<Long> idList) {
        if (CollectionUtil.isNotEmpty(idList)) {
            for (Long id : idList) {
                deleteById(id);
            }
        }
    }

    @Override
    public Long insert(StoreAllotRecord storeAllotRecord) {
        Date now = new Date();
        storeAllotRecord.setCreateTime(now);
        storeAllotRecord.setUpdateTime(now);
        return mapper.insert(storeAllotRecord) > 0 ? storeAllotRecord.getId() : 0L;
    }

    @Override
    public Long insertSelective(StoreAllotRecord storeAllotRecord) {
        Date now = new Date();
        storeAllotRecord.setCreateTime(now);
        storeAllotRecord.setUpdateTime(now);
        return mapper.insertSelective(storeAllotRecord) > 0 ? storeAllotRecord.getId() : 0L;
    }

    @Override
    public boolean update(StoreAllotRecord storeAllotRecord) {
        Date now = new Date();
        if (BeanUtil.isEmpty(storeAllotRecord.getCreateTime()))
            storeAllotRecord.setCreateTime(now);
        storeAllotRecord.setUpdateTime(now);
        return mapper.updateByPrimaryKey(storeAllotRecord) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(StoreAllotRecord record) {
        Date now = new Date();
        record.setUpdateTime(now);
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    @Transactional
    public boolean save(StoreAllotRecordSaveOrUpdateVo saveOrUpdateVo) {
        StoreAllotRecord storeAllotRecord = new StoreAllotRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, storeAllotRecord);
        storeAllotRecord.setNumber(createNextNumber());
        storeAllotRecord.setStatus(storeAllotRecord.getStatus() == null ? StoreEnum.StatusEnum.DRAFT.getCode().byteValue() : storeAllotRecord.getStatus());
        //产品信息
        List<StoreAllotRecordProductSaveOrUpdateVo> saveOrUpdateVoList = saveOrUpdateVo.getSaveOrUpdateVoList();
        //先保存入库单
        Long storeRecordId = this.insertSelective(storeAllotRecord);
        saveOrUpdateVo.setId(storeRecordId);
        for (StoreAllotRecordProductSaveOrUpdateVo storeOutRecordProductSaveOrUpdateVo : saveOrUpdateVoList) {
            //循环保存
            storeOutRecordProductSaveOrUpdateVo.setWarehouseInId(saveOrUpdateVo.getWarehouseInId());
            storeOutRecordProductSaveOrUpdateVo.setWarehouseOutId(saveOrUpdateVo.getWarehouseOutId());
            storeOutRecordProductSaveOrUpdateVo.setStoreAllotRecordId(storeRecordId);
            storeAllotRecordProductService.save(storeOutRecordProductSaveOrUpdateVo);
        }
        return storeRecordId != 0;
    }

    @Override
    @Transactional
    public boolean modify(StoreAllotRecordSaveOrUpdateVo saveOrUpdateVo) {
        if (BeanUtil.isEmpty(saveOrUpdateVo.getId()))
            return this.save(saveOrUpdateVo);
        StoreAllotRecord old = this.selectById(saveOrUpdateVo.getId());
        AssertCommonUtil.notNull(old, "此数据不存在或者已被删除");
        AssertCommonUtil.check(BeanUtil.isEmpty(saveOrUpdateVo.getSaveOrUpdateVoList()), "出库商品不能为空");
        AssertCommonUtil.check(old.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue(), "当前调拨单已审核通过，不能修改");
        StoreAllotRecord storeAllotRecord = new StoreAllotRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, storeAllotRecord);
        this.update(storeAllotRecord);
        storeAllotRecordProductService.deleteByCondition(StoreAllotRecordProductSearchVo.builder()
                .storeAllotRecordId(saveOrUpdateVo.getId())
                .build());
        //产品信息
        List<StoreAllotRecordProductSaveOrUpdateVo> storeRecordProductList = saveOrUpdateVo.getSaveOrUpdateVoList();
        if (BeanUtil.isNotEmpty(storeRecordProductList))
            for (StoreAllotRecordProductSaveOrUpdateVo productSaveOrUpdateVo : storeRecordProductList) {
                //循环保存
                productSaveOrUpdateVo.setStoreAllotRecordId(saveOrUpdateVo.getId());
                storeAllotRecordProductService.save(productSaveOrUpdateVo);
            }
        return true;
    }


    @Override
    public StoreAllotRecordVo selectOne(StoreAllotRecordSearchVo storeAllotRecordSearchVo) {
        return mapper.selectOne(storeAllotRecordSearchVo);
    }

    @Override
    public Integer count(StoreAllotRecordSearchVo storeAllotRecordSearchVo) {
        setAppStatusList(storeAllotRecordSearchVo);
        return mapper.count(storeAllotRecordSearchVo);
    }

    @Override
    public List<StoreAllotRecordVo> selectList(StoreAllotRecordSearchVo storeAllotRecordSearchVo) {
        setAppStatusList(storeAllotRecordSearchVo);
        return mapper.selectList(storeAllotRecordSearchVo);
    }

    private void setAppStatusList(StoreAllotRecordSearchVo storeRecordSearchVo) {
        List<Byte> list = new ArrayList<>();
        if (storeRecordSearchVo.getAppStatus() != null) {
            if (storeRecordSearchVo.getAppStatus() == 0) {
                list = Arrays.asList(
                        StoreEnum.StatusEnum.END.getCode().byteValue(),
                        StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue()
                );
            } else if (storeRecordSearchVo.getAppStatus() == 1) {
                list = Collections.singletonList(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue());
            } else if (storeRecordSearchVo.getAppStatus() == 2) {
                list = Collections.singletonList(StoreEnum.StatusEnum.END.getCode().byteValue());
            }
        }
        storeRecordSearchVo.setAppStatusList(list);
    }

    @Override
    public Page<StoreAllotRecordVo> selectPage(StoreAllotRecordSearchVo storeAllotRecordSearchVo) {
        AssertCommonUtil.check(Objects.isNull(storeAllotRecordSearchVo.getPageNum()) || Objects.isNull(storeAllotRecordSearchVo.getPageSize()), "分页参数不能为空");
        //先直接查总数
        int count = count(storeAllotRecordSearchVo);
        //分页
        Page<StoreAllotRecordVo> page = new Page<>(true, count, storeAllotRecordSearchVo.getPageNum(), storeAllotRecordSearchVo.getPageSize());
        storeAllotRecordSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<StoreAllotRecordVo> responseVos = this.selectList(storeAllotRecordSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public boolean insertBatch(List<StoreAllotRecord> entities) {
        return CollectionUtil.isNotEmpty(entities) && mapper.insertBatch(entities) > 0;
    }


    @Override
    public String selectMaxNumber() {
        return mapper.selectMaxNumberByDay(DateUtil.formatDate(new Date()));
    }

    @Override
    public String createNextNumber() {
        String maxCode = this.selectMaxNumber();
        if (StringUtils.isBlank(maxCode)) {
            return String.format("%s-%s-001", CodingEnum.PREFIX.DB.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")));
        }
        String[] maxCodeArray = maxCode.split("-");
        Integer i = Integer.valueOf(maxCodeArray[maxCodeArray.length - 1]);
        i++;
        return String.format("%s-%s-%s", CodingEnum.PREFIX.DB.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")), String.format("%03d", i));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional
    public boolean submitAudit(StoreAllotRecordSaveOrUpdateVo param) {
        modify(param);
        AssertCommonUtil.check(param.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue(), "已审核无法状态");
        AssertCommonUtil.check(BeanUtil.isEmpty(param.getSaveOrUpdateVoList()), "调拨商品明细不得为空");
        param.getSaveOrUpdateVoList().forEach(vo -> {
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseLocationOutId()), "产品明细中库位信息不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getStoreCount()), "产品明细中数量不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseLocationOutId()), "产品明细中仓库不得为空");
        });
        //出库仓库锁定校验
        Set<Long> warehouseOutIds = param.getSaveOrUpdateVoList().stream().map(StoreAllotRecordProductSaveOrUpdateVo::getWarehouseOutId).collect(Collectors.toSet());
        warehouseOutIds.forEach(p -> {
            StoreLockVo storeLock = storeLockService.selectByWarehouseId(p);
            AssertCommonUtil.check(Objects.equals(storeLock.getType(), StoreEnum.LOCK_TYPE.LOCK.getCode()), String.format("仓库%s已被锁定，无法提交调拨审核", storeLock.getWarehouseName()));
        });
        //入库仓库锁定校验
        Set<Long> warehouseIds = param.getSaveOrUpdateVoList().stream().map(StoreAllotRecordProductSaveOrUpdateVo::getWarehouseInId).collect(Collectors.toSet());
        warehouseIds.forEach(p -> {
            StoreLockVo storeLock = storeLockService.selectByWarehouseId(p);
            AssertCommonUtil.check(Objects.equals(storeLock.getType(), StoreEnum.LOCK_TYPE.LOCK.getCode()), String.format("仓库%s已被锁定，无法提交调拨审核", storeLock.getWarehouseName()));
        });
        this.updateByPrimaryKeySelective(StoreAllotRecord.builder()
                .id(param.getId())
                .status(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue())
                .build());
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional
    public boolean audit(StoreAllotRecordSaveOrUpdateVo param) {
        //modify(param);
        StoreAllotRecordVo storeAllotRecord = this.selectVoById(param.getId());
        AssertCommonUtil.check(storeAllotRecord.getStatus() != StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue(), "仅待审核状态可审核");
        if (param.getStatus() == StoreEnum.StatusEnum.END.getCode().byteValue()) {
            //审核通过 刷新商品状态
            List<StoreAllotRecordProductVo> storeAllotRecordProductVos = storeAllotRecord.getSaveOrUpdateVoList();
            //校验产品是否存在
            AssertCommonUtil.check(BeanUtil.isEmpty(storeAllotRecordProductVos), "该调拨单对应的产品记录不存在");
            //组装出库数据
            List<StockStorageDto> stockOutStorages = new ArrayList<>();
            List<StockStorageDto> stockInStorages = new ArrayList<>();
            for (StoreAllotRecordProductVo storeAllotRecordProductVo : storeAllotRecordProductVos) {
                stockOutStorages.add(StockStorageDto.builder()
                        .productId(storeAllotRecordProductVo.getProductId())
                        .warehouseLocationId(storeAllotRecordProductVo.getWarehouseLocationOutId())
                        .warehouseId(storeAllotRecordProductVo.getWarehouseOutId())
                        .count(storeAllotRecordProductVo.getStoreCount())
                        .build());
                stockInStorages.add(StockStorageDto.builder()
                        .productId(storeAllotRecordProductVo.getProductId())
                        .warehouseLocationId(storeAllotRecordProductVo.getWarehouseLocationInId())
                        .warehouseId(storeAllotRecordProductVo.getWarehouseInId())
                        .count(storeAllotRecordProductVo.getStoreCount())
                        .build());
            }

            //出库 保存操作记录 更新库存
            storeService.stockAction(StockActionDto.builder()
                    .actionType(StockActionEnum.ACTION_TYPE.ALLOT_OUT)
                    .stockStorages(stockOutStorages).voucherCode(storeAllotRecord.getNumber())
                    .optId(storeAllotRecord.getId())
                    .optSource(2)
                    .voucherTime(com.zhijian.util.DateUtil.getTime(com.zhijian.util.DateUtil.DATE_FORMAT))
                    .optUserId(param.getUpdateUserId())
                    .crtUserId(storeAllotRecord.getCreateUserId())
                    .build());
            //入库 保存操作记录 更新库存
            storeService.stockAction(StockActionDto.builder()
                    .actionType(StockActionEnum.ACTION_TYPE.ALLOT_IN)
                    .stockStorages(stockInStorages).voucherCode(storeAllotRecord.getNumber())
                    .optId(storeAllotRecord.getId())
                    .optSource(2)
                    .voucherTime(com.zhijian.util.DateUtil.getTime(com.zhijian.util.DateUtil.DATE_FORMAT))
                    .optUserId(param.getUpdateUserId())
                    .crtUserId(storeAllotRecord.getCreateUserId())
                    .build());
        }
        return updateByPrimaryKeySelective(StoreAllotRecord.builder()
                .rejectMsg(param.getRejectMsg())
                .status(param.getStatus())
                .id(param.getId())
                .updateUserId(param.getUpdateUserId())
                .build());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean inOutOpt(StoreAllotRecordProductInOrOutVo param, int sourceType) {
        StoreAllotRecordProduct storeAllotRecordProduct = storeAllotRecordProductService.selectById(param.getId());
        AssertCommonUtil.check(BeanUtil.isEmpty(storeAllotRecordProduct), "当前产品不存在");
        AssertCommonUtil.check(BeanUtil.isEmpty(param.getStatus()), "出库或者入库状态不能为空");
        AssertCommonUtil.check(!Arrays.asList(StoreEnum.ALLOT_PRODUCT_STATUS.OUT.getCode(), StoreEnum.ALLOT_PRODUCT_STATUS.IN.getCode()).contains(param.getStatus()), "当前产品非待出库状态，无法出库");
        StoreAllotRecord storeAllotRecord = this.selectById(storeAllotRecordProduct.getStoreAllotRecordId());
        AssertCommonUtil.check(BeanUtil.isEmpty(storeAllotRecord), "当前产品对应的调拨单不存在");
        Long warehouseId = storeAllotRecordProduct.getWarehouseOutId();
        Long warehouseLocationId = storeAllotRecordProduct.getWarehouseLocationOutId();
        if (Objects.equals(param.getStatus(), StoreEnum.ALLOT_PRODUCT_STATUS.IN.getCode())) {
            warehouseId = storeAllotRecord.getWarehouseInId();
            AssertCommonUtil.check(BeanUtil.isEmpty(storeAllotRecordProduct.getWarehouseLocationInId()), "入库库位不能为空");
            warehouseLocationId = storeAllotRecordProduct.getWarehouseLocationInId();
        }
        if (storeLockService.selectLock(warehouseId)) {
            Warehouse warehouse = warehouseService.selectById(warehouseId);
            AssertCommonUtil.check(true, String.format("仓库%s已被锁定，无法调拨出入库", warehouse.getName()));
        }
        //组装数据
        List<StockStorageDto> stockStorages = new ArrayList<>();
        stockStorages.add(StockStorageDto.builder().productId(storeAllotRecordProduct.getProductId())
                .warehouseLocationId(warehouseLocationId)
                .warehouseId(warehouseId)
                .count(storeAllotRecordProduct.getStoreCount())
                .build());
        StockActionDto action = StockActionDto.builder()
                .actionType(Objects.equals(param.getStatus(), StoreEnum.ALLOT_PRODUCT_STATUS.IN.getCode()) ? StockActionEnum.ACTION_TYPE.ALLOT_IN : StockActionEnum.ACTION_TYPE.ALLOT_OUT)
                .stockStorages(stockStorages).voucherCode(storeAllotRecord.getNumber())
                .optId(storeAllotRecord.getId())
                .optSource(sourceType)
                .voucherTime(com.zhijian.util.DateUtil.getTime(com.zhijian.util.DateUtil.DATE_FORMAT))
                .optUserId(param.getOptUserId())
                .crtUserId(storeAllotRecord.getCreateUserId())
                .build();
        //更新该商品状态
        storeAllotRecordProductService.updateByPrimaryKeySelective(StoreAllotRecordProduct.builder().id(param.getId()).status(param.getStatus() + 1).build());
        //保存操作记录 更新库存
        storeService.stockAction(action);
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<StoreVo> selectListWithStore(StoreAllotRecordProductSearchVoWithStore param) {
        String barCode = param.getBarCode();
        String rfId = param.getRfId();
        AssertCommonUtil.check(BeanUtil.isEmpty(barCode) && BeanUtil.isEmpty(rfId), "条码或者RFID不能均为空");
        String redisKey = "";


        List<ProductVo> productVos = productService.selectList(ProductSearchVo.builder()
                .barCode(param.getBarCode())
                .rfId(param.getRfId())
                .isDelete(DelFlagEnum.USING.value)
                .build());
        if (BeanUtil.isEmpty(productVos))
            return new ArrayList<>();
        List<StoreVo> storeVos = new ArrayList<>();
        for (ProductVo productVo : productVos) {
            List<StoreVo> storeVos1 = storeService.selectList(StoreSearchVo.builder()
                    .warehouseId(param.getWarehouseOutId())
                    .productId(productVo.getId())
                    .build());
            if (storeVos1 != null)
                storeVos.addAll(storeVos1);
        }
        return storeVos;
    }
}
